package com.osdp.common.security.filter;

import com.google.common.collect.Lists;
import com.osdp.auth.api.ITokenApi;
import com.osdp.common.constant.CommonConstant;
import com.osdp.common.http.Result;
import com.osdp.common.base.JWTInfo;
import com.osdp.common.util.HttpUtil;
import com.osdp.common.util.MessageUtil;
import com.osdp.common.util.TokenHolder;
import com.osdp.common.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.CollectionUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * BasicAuthenticationFilter ：请求头有basic开头的信息，base64解码后认证，认证成功则标记认证成功，否则进入下一认证过滤器
 * （前提是使用了httpbasic认证方式，如果使用HTTP form认证方式则不会进入此过滤器）
 */
@Slf4j
public class TokenVerifyFilter extends BasicAuthenticationFilter {

    @Autowired
    private ITokenApi tokenApi;

    public TokenVerifyFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    public TokenVerifyFilter(AuthenticationManager authenticationManager, ITokenApi tokenApi){
        this(authenticationManager);
        this.tokenApi = tokenApi;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (!isFeignRequest(request)) {
            String token = TokenHolder.getToken();
            if(token == null){
                log.error("token为空");
                HttpUtil.serverError(response, Result.fail(4015, MessageUtil.getMessage(10020)).toJson());
                return;
            }
            Boolean valid = tokenApi.verify(token);
            if(!valid){
                log.error("token失效");
                HttpUtil.serverError(response, Result.fail(4015, MessageUtil.getMessage(10021)).toJson());
                return;
            }
            JWTInfo info = TokenUtil.verify(token);
            if (null == info) {
                log.error("token未设置payload信息");
                HttpUtil.serverError(response, Result.fail(4015, MessageUtil.getMessage(10021)).toJson());
                return;
            }
//            if (!checkTenant(info)) {
//                HttpUtil.serverError(response, Result.fail(4015, MessageUtil.getMessage(403)).toJson());
//                return;
//            }
            List<SimpleGrantedAuthority> authorities = Lists.newArrayList();
            List<String> roles = info.getRoles();//取当前用户所属的所有角色
            // 所有角色编码加入前缀："ROLE_"
            if(!CollectionUtils.isEmpty(info.getRoles())){
                authorities = roles.stream().map(e->new SimpleGrantedAuthority(String.format(CommonConstant.PREFIX_ROLE_CODE+"%s",e))).collect(Collectors.toList());
            }
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(info, null, authorities);
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }

    private boolean isFeignRequest(HttpServletRequest request){
        String isFeign = request.getHeader(CommonConstant.FEIGN_INVOKER);
        return StringUtils.equals(isFeign, "true");
    }

    /**
     * Noacos 命名空间
     */
//    @Value("${spring.cloud.nacos.discovery.namespace}")
//    private String localTenant;
//
//    public boolean checkTenant(JWTInfo info){
//        List<String> tenants = info.getTenants();
//        if(CollectionUtils.isEmpty(tenants)){
//            return false;
//        }
//        return StringUtils.isEmpty(localTenant) || tenants.contains(localTenant);
//    }
}
